package com.wangch.sqlsession;

import com.wangch.pojo.Configuration;
import com.wangch.pojo.MappedStatement;
import com.wangch.utils.GenericTokenParser;
import com.wangch.utils.ParameterMapping;
import com.wangch.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor{
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        Connection connection = configuration.getDataSource().getConnection();
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappingList();
        Class clazz = getClassType(mappedStatement.getParameterType());
        for(int i = 0; i < parameterMappings.size(); i++){
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = clazz.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        Class<?> resultClass = getClassType(mappedStatement.getResultType());

        List<Object> objects = new ArrayList<Object>();
        while(resultSet.next()){
            Object o = resultClass.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for(int i = 1; i <= metaData.getColumnCount(); i++){
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            objects.add(o);
        }
        return (List<E>) objects;
    }

    public void insert(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception{
        Connection connection = configuration.getDataSource().getConnection();
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappingList();
        Class clazz = getClassType(mappedStatement.getParameterType());
        for(int i = 0; i < parameterMappings.size(); i++){
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = clazz.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        preparedStatement.execute();
    }

    public void update(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception{
        Connection connection = configuration.getDataSource().getConnection();
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappingList();
        Class clazz = getClassType(mappedStatement.getParameterType());
        for(int i = 0; i < parameterMappings.size(); i++){
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = clazz.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        preparedStatement.executeUpdate();
    }
    public void delete(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception{
        Connection connection = configuration.getDataSource().getConnection();
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappingList();
        Class clazz = getClassType(mappedStatement.getParameterType());
        for(int i = 0; i < parameterMappings.size(); i++){
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = clazz.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        preparedStatement.executeUpdate();
    }

    // 完成对#{}的解析工作： 1 将#{}使用?进行代替 2 解析出#{}的值进行存储
    public BoundSql getBoundSql(String sql){
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        String parseSql = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(parseSql, parameterMappings);
        return boundSql;
    }

    public Class<?> getClassType(String className) throws ClassNotFoundException {
        if(className != null)
            return Class.forName(className);
        return null;
    }



}




























